package network

import (
	"encoding/binary"
	"errors"
	"io"
	"math"
)

// 4字节设置包长度
const packLen = 4

// MsgParser
// --------------
// | len | data |
// --------------
type MsgParser struct{}

func NewMsgParser() *MsgParser {
	p := new(MsgParser)
	return p
}

// goroutine safe
func (p *MsgParser) Read(conn *TCPConn) ([]byte, error) {
	var b [4]byte
	bufMsgLen := b[:packLen]

	// read len
	if _, err := io.ReadFull(conn, bufMsgLen); err != nil {
		return nil, err
	}

	// parse len
	var msgLen = binary.BigEndian.Uint32(bufMsgLen)

	// check len
	if msgLen > math.MaxInt32 {
		return nil, errors.New("message too long")
	} else if msgLen < 0 {
		return nil, errors.New("message too short")
	}

	// data
	msgData := make([]byte, msgLen)
	if _, err := io.ReadFull(conn, msgData); err != nil {
		return nil, err
	}

	return msgData, nil
}

// goroutine safe
func (p *MsgParser) Write(conn *TCPConn, args ...[]byte) error {
	// get len
	var msgLen uint32
	for i := 0; i < len(args); i++ {
		msgLen += uint32(len(args[i]))
	}

	// check len
	if msgLen > math.MaxInt32 {
		return errors.New("message too long")
	} else if msgLen < 0 {
		return errors.New("message too short")
	}

	msg := make([]byte, packLen+msgLen)

	// write len
	binary.BigEndian.PutUint32(msg, msgLen)

	// write data
	l := packLen
	for i := 0; i < len(args); i++ {
		copy(msg[l:], args[i])
		l += len(args[i])
	}

	conn.Write(msg)

	return nil
}
